#include "polygon.h"
#include <algorithm>
#include <iostream>

polygon::polygon(const simple_polygon& p) : points(p)
{
}

std::istream& operator >>(std::istream& in, simple_polygon &p)
{
    size_t n;
    in >> n;
    point point_;
    for (size_t i = 0; i < n; i++)
    {
        in >> point_;
        p.push_back(point_);
    }

    return in;
}

std::istream& operator >>(std::istream& in, polygon& p)
{
   in >> p.points;

   size_t m;
   in >> m;
   simple_polygon tmp;
   for (size_t i = 0; i < m; i++)
   {
       in >> tmp;
       p.holes.push_back(tmp);
   }

   return in;
}

// -1 - bound
int polygon::count_simple(const simple_polygon &points, const point &p) const
{
    size_t count = 0;
    size_t n = points.size();
    for (size_t i = 0; i < n; i++)
    {
        point p1 = points[i];
        point p2 = points[(i + 1) % n];

        if (p1.x > p2.x || (p1.x == p2.x && p1.y > p2.y))
            std::swap(p1, p2);


        if (p1.x == p2.x && p1.x == p.x)
        {
            if (p1.y <= p.y && p.y <= p2.y)
                return -1; // bound
            else if (p.y <= p1.y)
                count++;
        }

        if ((p1.x <= p.x) && (p.x < p2.x) && (left_turn(p, p1, p2) == NEGATIVE))
            count++;
    }

    return count;
}

sign polygon::is_inside(const point &p) const
{
    int count = count_simple(points, p);

    if (count < 0)
        return BOUND;
    else
        for (size_t i = 0; i < holes.size(); i++)
        {
            int tmp = count_simple(holes[i], p);
            if (tmp < 0)
                return BOUND;
            else
                count += tmp;
        }

    if (count % 2 == 0)
        return OUT;
    else
        return INSIDE;
}

namespace {
template<typename T>
bool between(const T& a, const T& b, const T& c)
{
    return (a <= b && b <= c) || (c <= b && b <= a);
}
}

sign polygon::is_inside_convex_polygon(const point& p) const
{
    if (left_turn(points[0], points[1], p) == POSITIVE
      ||left_turn(points[1], points[2], p) == POSITIVE)
        return NO;

    simple_polygon::const_iterator it = std::lower_bound(points.begin() + 1, points.end(), p, cmp(points[0]));

    if (it == points.end())
        return NO;

    point p2 = *it;
    point p1 = it[-1];

    sign lt = left_turn(p1, p2, p);

    return (lt != POSITIVE) ? YES : NO;
}

polygon::cmp::cmp(const point& start_) : start(start_)
{}

bool polygon::cmp::operator() (const point& p, const point& p1) const
{
    return left_turn(start, p, p1) < 0;
}
